home *** CD-ROM | disk | FTP | other *** search
/ System Booster / System Booster.iso / Mousetools / ButExchange / ButExchange.asm < prev    next >
Assembly Source File  |  1996-09-26  |  14KB  |  556 lines

  1. *    ButExchange
  2. *    By Preben Nielsen
  3. *
  4. *      This program is intended as a help to left-handed Amiga-users.
  5. *    It installes an input-handler which reverses the function of the
  6. *    mouse buttons, so that the left button becomes the right and
  7. *    vice versa.
  8. *
  9. *      Once installed, the program only uses 168 bytes of memory. To
  10. *    get back to normal simply run the program again.
  11. *
  12. *    NOTE:    There's no need to 'RUN' or 'RUNBACK' this program from the
  13. *        CLI. It terminates immediately.
  14. *
  15. *HISTORY
  16. *          Made with Hisoft V2.12
  17. *
  18. *  V1.0   09-Apr-91: First attempt. Works of course.
  19. *  V1.1   19-May-91: Help, I just found out that my "TellInputDevice"
  20. *                    routine trashes memory-address 0 because it didn't
  21. *                    do a "NewList" on its Message-port. It didn't cause
  22. *                    any problems most of the time, but it has now been
  23. *                    cured.
  24.  
  25.                    
  26.     OPT O+
  27.     OPT O1+            ; Tells when a branch could be optimised to short
  28.     OPT i+            ; Tells when '#' is probably missing
  29.  
  30.         incdir        "AsmInc:"
  31.         include        "exec/exec_lib.i"
  32.         include        "exec/io.i"
  33.         include        "exec/memory.i"
  34.         include        "exec/interrupts.i"
  35.         include        "devices/input.i"
  36.         include        "devices/inputevent.i"
  37.         include        "libraries/dosextens.i"
  38.         include        "libraries/dos_lib.i"
  39.  
  40. Prepare        MACRO
  41.         IFC        '\1','Exec_Call'
  42.         movea.l        4.W,A6
  43.         ENDC
  44.         IFC        '\1','Intuition_Call'
  45.         movea.l        IntBase(DB),A6
  46.         ENDC
  47.         IFC        '\1','Gfx_Call'
  48.         movea.l        GfxBase(DB),A6
  49.         ENDC
  50.         IFC        '\1','Dos_Call'
  51.         movea.l        DosBase(DB),A6
  52.         ENDC
  53.         ENDM
  54. CallLib        MACRO
  55.         jsr        _LVO\1(A6)
  56.         ENDM
  57. Call        MACRO
  58.         bsr        \1
  59.         ENDM
  60. CallS        MACRO
  61.         bsr.S        \1
  62.         ENDM
  63. Push        MACRO
  64.         movem.l        \1,-(SP)
  65.         ENDM
  66. Pop        MACRO
  67.         movem.l        (SP)+,\1
  68.         ENDM
  69. rAPtr        MACRO        name
  70. DefSiz        set        DefSiz+4
  71. DefPtr        set        DefPtr-4
  72. \1        =        DefPtr
  73.         ENDM
  74. rLong        MACRO        name
  75. DefSiz        set        DefSiz+4
  76. DefPtr        set        DefPtr-4
  77. \1        =        DefPtr
  78.         ENDM
  79. rWord        MACRO        name
  80. DefSiz        set        DefSiz+2
  81. DefPtr        set        DefPtr-2
  82. \1        =        DefPtr
  83.         ENDM
  84. rByte        MACRO        name
  85. DefSiz        set        DefSiz+1
  86. DefPtr        set        DefPtr-1
  87. \1        =        DefPtr
  88.         ENDM
  89. rStorage    MACRO        name,size    ; Define storage
  90. DefSiz        set        DefSiz+\2
  91. DefPtr        set        DefPtr-\2
  92. \1        =        DefPtr
  93.         ENDM
  94. rEVEN        MACRO                ; Word boundary
  95.         IFNE        DefPtr&1
  96. DefPtr        set        DefPtr-1
  97. DefSiz        set        DefSiz+1
  98.         ENDC
  99.         ENDM
  100. rStart        MACRO                ; Define var section
  101. DefPtr        set        0
  102. DefSiz        set        0
  103.         ENDM
  104. rEnd        MACRO                ; End var section
  105. RelSize        =        DefSiz
  106.         ENDM
  107. rAlloc        MACRO                ; Allocate vars
  108.         link        DB,#-RelSize
  109.         ENDM
  110. rFree        MACRO                ; Deallocate vars
  111.         unlk        DB
  112.         ENDM
  113. rClear        MACRO                ; Reset all vars
  114.         movem.l        D0/DB,-(SP)
  115.         move.w        #RelSize-1,D0
  116. rClr.\@        clr.b        -(DB)
  117.         dbf        D0,rClr.\@
  118.         movem.l        (SP)+,D0/DB
  119.         ENDM
  120.  
  121. DB        EQUR        A4
  122.  
  123.         SECTION        ButExchange,CODE
  124. InitProcess    rAlloc                    ; Allocate memory for variables
  125.         rClear                    ; Clear the memory
  126.         Prepare        Exec_Call
  127.         suba.l        A1,A1
  128.         CallLib        FindTask        ; Find us
  129.         move.l        D0,PProcess(DB)
  130.         movea.l        D0,A2
  131.         tst.l        pr_CLI(A2)
  132.         bne.S        GetLibs
  133. WBStart        lea        pr_MsgPort(A2),A0
  134.         CallLib        WaitPort        ; wait for a message
  135.         lea        pr_MsgPort(A2),A0
  136.         CallLib        GetMsg            ; then get it
  137.         move.l        D0,WBMsg(DB)        ; save it for later reply
  138. GetLibs        lea        DosName(PC),A1
  139.         CallLib        OldOpenLibrary
  140.         move.l        D0,DosBase(DB)
  141.         beq.S        Error
  142.  
  143.         CallLib        Forbid
  144.         lea        IHS(PC),A1
  145.         lea        ihs_PortName(A1),A1
  146.         CallLib        FindPort
  147.         move.l        D0,D2
  148.         CallLib        Permit
  149.         move.l        D2,D0            ; Does Forbid/Permit destroy scratch-registers ?
  150.         beq.S        DoInstall
  151. DoRemove    moveq        #REMOVED,D7
  152.         lea        IHS(PC),A0
  153.         lea        PSEndIHS1(PC),A1
  154.         lea        PSEndIHS2(PC),A2
  155.         Call        RemoveHandler
  156.         beq.S        ShowMsg
  157.         moveq        #CANTREMOVE,D7
  158.         bra.S        ShowMsg
  159. DoInstall    moveq        #INSTALLED,D7
  160.         lea        IHS(PC),A0
  161.         lea        PSPrepIHS1(PC),A1
  162.         lea        PSPrepIHS2(PC),A2
  163.         Call        InstallHandler
  164.         beq.S        ShowMsg
  165.         moveq        #CANTINSTALL,D7
  166. ShowMsg        move.l        D7,D0
  167.         Call        CONMsg
  168.  
  169. Error
  170. Exit        Prepare        Exec_Call
  171. FreeDos        move.l        DosBase(DB),D0
  172.         beq.S        ReplyWB
  173.         move.l        D0,A1
  174.         CallLib        CloseLibrary
  175. ReplyWB        move.l        WBMsg(DB),D2
  176.         beq.S        AllDone
  177.         CallLib        Forbid            ; We were started from WB
  178.         movea.l        D2,A1
  179.         CallLib        ReplyMsg        ; Reply WBMessage
  180. AllDone        rFree
  181.         moveq        #0,D0
  182.         rts
  183.  
  184. FHandle        EQUR        D5
  185. * Call: D0 = Msg-number
  186. CONMsg        Push        D0-D7/A0-A6
  187.         Prepare        Dos_Call
  188.         move.l        D0,D4
  189.         moveq        #0,D6
  190.         CallLib        Output
  191.         move.l        D0,FHandle
  192.         bne.S        1$
  193.         moveq        #1,D6
  194.         lea        CONName(PC),A0
  195.         move.l        A0,D1
  196.         move.l        #MODE_OLDFILE,D2
  197.         CallLib        Open
  198.         move.l        D0,FHandle
  199.         beq.S        2$
  200. 1$        moveq        #INFOMSG,D0
  201.         Call        SendMsg
  202.         move.l        D4,D0
  203.         Call        SendMsg
  204.         tst.l        D6
  205.         beq.S        2$
  206.         moveq        #127,D1
  207.         CallLib        Delay
  208.         move.l        FHandle,D1
  209.         CallLib        Close
  210. 2$        Pop        D0-D7/A0-A6
  211.         rts
  212.  
  213. * Call: D0 = Msg-number
  214. SendMsg        neg.l        D0
  215.         lsl.l        #1,D0
  216.         lea        MsgTable(PC),A0
  217.         add.w        0(A0,D0),A0
  218.         move.l        A0,D2
  219.         moveq        #-1,D3
  220. 1$        addq.l        #1,D3
  221.         tst.b        (A0)+
  222.         bne.S        1$
  223.         move.l        FHandle,D1
  224.         Prepare        Dos_Call
  225.         CallLib        Write
  226.         rts
  227.  
  228. INFOMSG        =0
  229. INSTALLED    =-1
  230. REMOVED        =-2
  231. CANTINSTALL    =-3
  232. CANTREMOVE    =-4
  233.  
  234. MsgText        MACRO
  235.         dc.w        \1-MsgTable
  236.         ENDM
  237. MsgTable    MsgText        Msg
  238.         MsgText        Msg1
  239.         MsgText        Msg2
  240.         MsgText        Msg3
  241.         MsgText        Msg4
  242.  
  243. CONName        dc.b        'CON:100/60/330/63/ButExchange',0
  244. Msg        dc.b        10,$9B,'0;33m ButExchange V1.1',10
  245.         dc.b        $9B,'0;31m 1991 by ',$9B,'0;33mPreben Nielsen',$9B,'0;31m',10,' ',0
  246. Msg1        dc.b        'has just been installed...',10,0
  247. Msg2        dc.b        'has just been removed...',10,0
  248. Msg3        dc.b        'Error: Cannot install handler',10,0
  249. Msg4        dc.b        'Error: Cannot remove handler',10,0
  250.         EVEN
  251.  
  252. rtsValue    EQUR        D7
  253. * This is general-purpose inputhandler removal-routine
  254. * It only needs an ihs with a port-name to remove the handler
  255. * Call:   A0 = ihs
  256. *      A1 = first ihs-installation-routine or NULL
  257. *      A2 = second ihs-installation-routine or NULL
  258. * Return: D0 = 0 means succes
  259. RemoveHandler    Push        D1/rtsValue/A0-A3/A6
  260.         moveq        #-1,rtsValue
  261.         move.l        A2,A3
  262.         move.l        A0,A2
  263.         move.l        A1,D1
  264.         beq.S        1$
  265.         jsr        (A1)        ; A0 = ihs
  266.         beq.S        2$
  267.         move.l        D0,A2
  268. 1$        move.l        A2,A0
  269.         Prepare        Exec_Call
  270.         moveq        #IND_REMHANDLER,D0
  271.         Call        TellInputDevice
  272.         move.l        D0,rtsValue
  273.         bne.S        2$
  274.         lea        ihs_Port(A2),A1
  275.         CallLib        RemPort
  276.         moveq        #0,D0
  277.         bra.S        3$
  278. 2$        moveq        #-1,D0
  279. 3$        move.l        A3,D1
  280.         beq.S        4$
  281.         move.l        A2,A0
  282.         jsr        (A3)        ; A0 = ihs, D0 = 0 means succes
  283. 4$        move.l        rtsValue,D0
  284.         Pop        D1/rtsValue/A0-A3/A6
  285.         rts
  286.  
  287. * This is general-purpose inputhandler installation-routine
  288. * It only needs an ihs with a port-name to install the handler
  289. * Call:   A0 = ihs
  290. *      A1 = first ihs-installation-routine or NULL
  291. *      A2 = second ihs-installation-routine or NULL
  292. * Return: D0 = 0 means succes
  293. InstallHandler    Push        D1/rtsValue/A0-A3/A6
  294.         moveq        #-1,rtsValue
  295.         move.l        A2,A3
  296.         move.l        A0,A2
  297.         move.l        A1,D1
  298.         beq.S        1$
  299.         jsr        (A1)        ; A0 = ihs
  300.         beq.S        2$
  301.         move.l        D0,A2
  302. 1$        move.l        A2,A0
  303.         moveq        #IND_ADDHANDLER,D0
  304.         Call        TellInputDevice
  305.         move.l        D0,rtsValue
  306.         bne.S        2$
  307.         lea        ihs_Port(A2),A1
  308.         lea        ihs_PortName(A2),A0
  309.         move.l        A0,MP+LN_NAME(A1)        ;MsgPort->mp_Node.ln_Name=Name;
  310.         clr.b        MP+LN_PRI(A1)            ;MsgPort->mp_Node.ln_Pri =0;
  311.         move.b        #NT_MSGPORT,MP+LN_TYPE(A1)    ;MsgPort->mp_Node.ln_Type=NT_MSGPORT;
  312.         move.b        #PA_IGNORE,MP_FLAGS(A1)        ;MsgPort->mp_Flags     =PA_IGNORE;
  313.         Prepare        Exec_Call
  314.         CallLib        AddPort
  315.         moveq        #0,D0
  316.         bra.S        3$
  317. 2$        moveq        #-1,D0
  318. 3$        move.l        A3,D1
  319.         beq.S        4$
  320.         move.l        A2,A0
  321.         jsr        (A3)        ; A0 = ihs, D0 = 0 means succes
  322. 4$        move.l        rtsValue,D0
  323.         Pop        D1/rtsValue/A0-A3/A6
  324.         rts
  325.  
  326. * Open the input device. Set up the I/O block to add or remove the
  327. * input handler, and send the request to the input device. Finally,
  328. * close the device
  329. * Call:   A0 = ihs
  330. *      D0 = Function to perform (IND_ADDHANDLER/IND_REMHANDLER)
  331. * Return: D0 = 0 means succes
  332. TellInputDevice    Push        D1-D2/rtsValue/A0-A3/A6
  333.         Prepare        Exec_Call
  334.         moveq        #-1,rtsValue
  335.         move.l        D0,D2
  336.         move.l        A0,A2
  337.         lea        IReq(DB),A0
  338.         moveq        #IOSTD_SIZE,D0
  339.         Call        MemClear
  340.         lea        IPort(DB),A0
  341.         moveq        #MP_SIZE,D0
  342.         Call        MemClear
  343.         move.l        A0,A3
  344.         move.b        #NT_MSGPORT,MP+LN_TYPE(A3)    ; mp_Node.ln_Type=NT_MSGPORT;
  345.         move.b        #PA_SIGNAL,MP_FLAGS(A3)        ; mp_Flags    =PA_SIGNAL;
  346.         moveq        #-1,D0
  347.         CallLib        AllocSignal
  348.         move.b        D0,MP_SIGBIT(A3)        ; mp_SigBit    =MPSigBit;
  349.         bmi.S        2$
  350.         suba.l        A1,A1
  351.         CallLib        FindTask
  352.         move.l        D0,MP_SIGTASK(A3)        ; mp_SigTask     =FindTask(0);
  353.         lea        MP_MSGLIST(A3),A0
  354.         NEWLIST        A0
  355.         lea        IReq(DB),A1
  356.         move.l        A3,IO+MN_REPLYPORT(A1)        ; ExtReq->io_Message.mn_ReplyPort   =taskReplyPort;
  357.         move.b        #NT_MESSAGE,IO+MN+LN_TYPE(A1)    ; ExtReq->io_Message.mn_Node.ln_Type=NT_MESSAGE;
  358.         lea        InputName(PC),A0        ; input.device
  359.         moveq        #0,D0                ; unit#
  360.         moveq        #0,D1                ; flags
  361.         CallLib        OpenDevice
  362.         tst.w        D0                ; flag: error if > 0
  363.         bne.S        1$
  364.         lea        IReq(DB),A1
  365.         move.w        D2,IO_COMMAND(A1)
  366.         lea        ihs_Interrupt(A2),A0
  367.         move.l        A0,IO_DATA(A1)
  368.         CallLib        DoIO
  369.         move.l        D0,rtsValue
  370.         lea        IReq(DB),A1
  371.         CallLib        CloseDevice
  372. 1$        move.b        MP_SIGBIT(A3),D0
  373.         CallLib        FreeSignal
  374. 2$        move.l        rtsValue,D0
  375.         Pop        D1-D2/rtsValue/A0-A3/A6
  376.         rts
  377.  
  378. * Call: A0    = Memory area
  379. *    D0:16 = Count
  380. MemClear    Push        D0-D1/A0
  381.         moveq        #0,D1
  382.         bra.S        2$
  383. 1$        move.b        D1,(A0)+
  384. 2$        dbf        D0,1$
  385.         Pop        D0-D1/A0
  386.         rts
  387.  
  388. * Call: A0   = Source
  389. *    A1   = Destination
  390. *    D0:16= Count
  391. MemCopy        Push        D0/A0-A1
  392.         bra.S        2$
  393. 1$        move.b        (A0)+,(A1)+
  394. 2$        dbf        D0,1$
  395.         Pop        D0/A0-A1
  396.         rts
  397.  
  398. * Each handler should have such a pair of installation-routine
  399. * The first one is passed to InstallHandler in A1 and it
  400. * is called immediately when entering InstallHandler
  401. * The second one is passed to InstallHandler in A2 and it
  402. * is called after attempt to install handler and message-port
  403. * -----------------------------------------------------------------
  404. * Call:   A0 = ihs
  405. * Return: D0 has to point to ihs to be used when installation proceeds
  406. *      If D0 = 0 then installation is aborted
  407. PSPrepIHS1    Push        D1/A0-A1/A6
  408.         Prepare        Exec_Call
  409.         move.l        #HandlerSize,D0
  410.         move.l        #MEMF_PUBLIC|MEMF_CLEAR,D1
  411.         CallLib        AllocMem
  412.         move.l        D0,HMem(DB)
  413.         beq.S        2$
  414.         move.l        D0,A1
  415.         lea        IHS(PC),A0
  416.         move.l        #HandlerSize,D0
  417.         Call        MemCopy
  418.         move.l        D0,ihs_Length(A1)        ; This will enable removal by other programs
  419.         lea        HandlerCode-IHS(A1),A0
  420.         move.l        A0,ihs_Interrupt+IS_CODE(A1)    ; HandlerBlock.HInterrupt.is_Code = Handler
  421.         clr.l        ihs_Interrupt+IS_DATA(A1)    ; HandlerBlock.HInterrupt.is_Data = 0
  422.         move.b        #HPRI,ihs_Interrupt+LN_PRI(A1)    ; HandlerBlock.HInterrupt.is_Node.ln_Pri = PRI
  423.         move.l        A1,D0
  424. 2$        Pop        D1/A0-A1/A6
  425.         rts
  426.  
  427. * Call:   A0 = ihs
  428. *         D0 = 0 means everything went perfect
  429. *             -1 means something went wrong during installation
  430. PSPrepIHS2    Push        D0-D1/A0-A1/A6
  431.         tst.l        D0
  432.         beq.S        1$
  433.         move.l        HMem(DB),D0
  434.         beq.S        1$
  435.         move.l        D0,A1
  436.         move.l        #HandlerSize,D0
  437.         Prepare        Exec_Call
  438.         CallLib        FreeMem
  439. 1$        Pop        D0-D1/A0-A1/A6
  440.         rts
  441.  
  442. * Each handler should have such a pair of ending-routine
  443. * The first one is passed to RemoveHandler in A1 and it
  444. * is called immediately when entering RemoveHandler
  445. * The second one is passed to RemoveHandler in A2 and it
  446. * is called after attempt to remove handler and message-port
  447. * -----------------------------------------------------------------
  448. * Call:   A0 = ihs
  449. * Return: D0 has to point to ihs to be used when removal proceeds
  450. *      If D0 = 0 then removal is aborted
  451. PSEndIHS1    Push        D1-D2/A0-A1/A6
  452.         Prepare        Exec_Call
  453.         CallLib        Forbid
  454.         lea        ihs_PortName(A0),A1
  455.         CallLib        FindPort
  456.         move.l        D0,D2
  457.         CallLib        Permit
  458.         move.l        D2,D0            ; Does Forbid/Permit destroy scratch-registers ?
  459.         Pop        D1-D2/A0-A1/A6
  460.         rts
  461. * Call:   A0 = ihs
  462. *         D0 = 0 means everything went perfect
  463. *             -1 means something went wrong during removal
  464. PSEndIHS2    Push        D0-D1/A0-A1/A6
  465.         tst.l        D0
  466.         bmi.S        1$
  467.         Prepare        Exec_Call
  468.         move.l        ihs_Length(A0),D0
  469.         move.l        A0,A1
  470.         CallLib        FreeMem
  471. 1$        Pop        D0-D1/A0-A1/A6
  472.         rts
  473.  
  474. *====================== Input-handler start =========================
  475. ihs_Port    =0
  476. ihs_Interrupt    =MP_SIZE
  477. ihs_ID        =MP_SIZE+IS_SIZE
  478. ihs_Length    =MP_SIZE+IS_SIZE+4
  479. ihs_Flags    =MP_SIZE+IS_SIZE+8
  480. ihs_PortName    =MP_SIZE+IS_SIZE+10
  481.  
  482. ihs_Start    MACRO
  483.         dcb.b        MP_SIZE        ; Message-Port structure
  484.         dcb.b        IS_SIZE        ; Interrupt structure
  485.         dc.l        'P_IH'        ; ID (Handler made by me)
  486.         dc.l        0        ; Length of handler 
  487.         dc.w        0        ; Flags
  488.         dc.b        \1,0
  489.         EVEN
  490.         ENDM
  491.  
  492. HPRI        =127                ; Handler-priority
  493. HDisabled    =0
  494. HNoExtRemoval    =1                ; Future
  495.  
  496. * This is the handler-block
  497. IHS        ihs_Start    <'ButExchange V1.1 Port'>
  498. * For each event in the event list:
  499. *  If it is LMB event then make it a RMB event and vice versa.
  500. * When all the events have been checked, return the event list so that
  501. * others can do their things.
  502. EList        EQUR    A0
  503. Event        EQUR    A1
  504.  
  505. Next        =ie_NextEvent
  506. Class        =ie_Class
  507. Code        =ie_Code
  508. Qual        =ie_Qualifier
  509.  
  510. * Call:  A0 = List of InputEvents, A1 = HandlerData
  511. HandlerCode    Push        D1/Event/EList
  512.         move.w        IHS+ihs_Flags(PC),D0
  513.         btst        #HDisabled,D0        ; Future feature
  514.         bne.S        NoMoreEvents
  515.         move.l        EList,Event
  516. ieLoop        move.l        Event,D0
  517.         beq.S        NoMoreEvents
  518.         cmpi.b        #IECLASS_RAWMOUSE,Class(Event)
  519.         bne.S        DontRemove
  520.         move.w        Code(Event),D0
  521.         move.w        D0,D1
  522.         andi.w        #IECODE_UP_PREFIX,D1
  523.         andi.w        #~IECODE_UP_PREFIX,D0
  524.         cmpi.w        #IECODE_LBUTTON,D0
  525.         beq.S        ExchangeLR
  526.         cmpi.w        #IECODE_RBUTTON,D0
  527.         bne.S        DontRemove
  528. ExchangeRL    ori.w        #IECODE_LBUTTON,D1
  529.         bra.S        Exchanged
  530. ExchangeLR    ori.w        #IECODE_RBUTTON,D1
  531. Exchanged    move.w        D1,Code(Event)
  532. * Just move on to next Event
  533. DontRemove    move.l        Next(Event),Event
  534.         bra.S        ieLoop
  535. * Lets return
  536. NoMoreEvents    move.l        EList,D0
  537.         Pop        D1/Event/EList
  538.         rts
  539. HandlerSize    =        *-IHS
  540. *====================== Input-handler end ===========================
  541.  
  542. *====================== Data-definition start =======================
  543.  rStart
  544.  rAPtr        PProcess
  545.  rAPtr        WBMsg
  546.  rAPtr        DosBase
  547.  rStorage    IReq,IOSTD_SIZE
  548.  rStorage    IPort,MP_SIZE
  549.  rAPtr        HMem
  550.  rEnd
  551.  
  552. DosName        dc.b        'dos.library',0
  553. InputName    dc.b        'input.device',0
  554.         END
  555.  
  556.